package cs342.project1.mathNotebook.tests.data;

import static org.junit.Assert.*;

import java.io.*;
import java.util.*;

import org.junit.Before;
import org.junit.Test;

import cs342.project1.mathNotebook.data.*;
import cs342.project1.mathNotebook.notebook.NotebookEntry;

/**
 * Tests the read/write functionality of the Notebook Repository
 * 
 * @author Jared Schlicht
 */
public class NotebookRepositoryTests {
	private final double delta = 0.001;
	private ByteArrayOutputStream outputStream;
	
	/**
	 * Re-initializes the repository with fresh in-memory collections
	 * 
	 * @throws Exception
	 * @author Jared Schlicht
	 */
	@Before
	public void setUp() throws Exception {
		this.outputStream = new ByteArrayOutputStream();
	}
	/**
	 * Verifies a basic file can be saved
	 */
	@Test
	public void testCompression() throws IOException {
		
		GZip.zip("test.xml");
		GZip.unzip("test.gz");
		
		FileInputStream stream = new FileInputStream("test.xml");
		
		String result = stream.toString();
		
		assertEquals(
				"Must match expected output",
				"<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"></formula></notebook>",
				result);
	}

	@Test
	public void testEncryption() throws IOException {
		
		Encryption.encrypt("test.xml","password","outputtest.dat");
		Encryption.decrypt("outputtest.dat","password","test.xml");
		
		FileInputStream stream = new FileInputStream("test.xml");
		
		String result = stream.toString();
		
		assertEquals(
				"Must match expected output",
				"<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"></formula></notebook>",
				result);
	}
	
	/**
	 * Ensures a blank notebook can be saved
	 */
	@Test
	public void testBlankSave() {
	    	XMLNotebookWriter writer = new XMLNotebookWriter(this.outputStream);

		List<NotebookEntry> entries = new ArrayList<NotebookEntry>();
		writer.writeAll(entries);
		
		String result = this.outputStream.toString();

		assertEquals(
				"Must match expected output",
				"<?xml version=\"1.0\" ?><notebook></notebook>",
				result);
	}

	/**
	 * Ensures data can be read back from XML
	 */
	@Test
	public void testGetAll() {
		String expected = "<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"></formula></notebook>";
		
		InputStream inputStream = new ByteArrayInputStream(expected.getBytes());
		XMLNotebookReader reader = new XMLNotebookReader(inputStream);
		
		List<NotebookEntry> entries = reader.getAll();
		assertTrue("The entries list must not be null", entries != null);
		assertTrue("There must be one entry in the notebook", entries.size() == 1);
		NotebookEntry entry = entries.get(0);
		assertTrue(entry.functionString.equals("2x+3"));
	}
	
	/**
	 * Tests the reading of tangent points
	 * @author Jared Schlicht
	 */
	@Test
	public void testWriteTangents() {
		List<NotebookEntry> entries = new ArrayList<NotebookEntry>();
		NotebookEntry entry = new NotebookEntry();
		entry.functionString = "2x+3";
		entry.tangentPoints.add(4.5);
		entry.tangentPoints.add(-1.22);
		entries.add(entry);

		XMLNotebookWriter writer = new XMLNotebookWriter(this.outputStream);
		writer.writeAll(entries);
		
		String result = this.outputStream.toString();
		
		assertEquals(
				"Must match expected output",
				"<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"><tangent point=\"4.5\"></tangent><tangent point=\"-1.22\"></tangent></formula></notebook>",
				result);
	}
	
	/**
	 * Tests the reading of tangent points
	 * @author Jared Schlicht
	 */
	@Test
	public void testReadTangents() {
		String expected = "<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"><tangent point=\"4.5\"></tangent><tangent point=\"-1.22\"></tangent></formula></notebook>";
		
		InputStream inputStream = new ByteArrayInputStream(expected.getBytes());
		XMLNotebookReader reader = new XMLNotebookReader(inputStream);
		
		List<NotebookEntry> entries = reader.getAll();
		assertTrue("The entries list must not be null", entries != null);
		assertTrue("There must be one entry in the notebook", entries.size() == 1);
		NotebookEntry entry = entries.get(0);
		
		assertTrue("There must be two tangent points in the entry", entry.tangentPoints.size() == 2);
		assertEquals("Tangent point 1 must be 4.5", 4.5, entry.tangentPoints.get(0), delta);
		assertEquals("Tangent point 2 must be -1.22", -1.22, entry.tangentPoints.get(1), delta);
	}
	
	@Test
	public void testSimpleSave() {
		List<NotebookEntry> entries = new ArrayList<NotebookEntry>();
		NotebookEntry entry = new NotebookEntry();
		entry.functionString = "2x+3";
		entry.tangentPoints.add(4.5);
		entry.tangentPoints.add(-1.22);
		entries.add(entry);

		XMLNotebookWriter writer = new XMLNotebookWriter(this.outputStream);
		writer.writeAll(entries);
		
		String result = this.outputStream.toString();
		
		assertEquals(
				"Must match expected output",
				"<?xml version=\"1.0\" ?><notebook><formula equation=\"2x+3\"><tangent point=\"4.5\"></tangent><tangent point=\"-1.22\"></tangent></formula></notebook>",
				result);
	}
}
